/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 *
 */

import fs from 'fs';
import path from 'path';

import { hvigorCore, Json5Reader } from '@ohos/hvigor';
import { HvigorConsoleLogger } from '@ohos/hvigor-logger';
import { PackageJson } from 'type-fest';

import { CommonConst } from '../const/common-const.js';
import { ProjectModel } from '../model/project/project-model.js';
import { Dependency, DependencyEnum } from '../project/dependency/core/dependency-interface.js';
import { DependencyManager } from '../project/dependency/dependency-manager.js';
import { ModuleTaskService } from '../tasks/service/module-task-service.js';
import { TargetTaskService } from '../tasks/service/target-task-service.js';
import { OhPackageJsonOpt } from '../tasks/task/ohos-har-task.js';
import { pathParamsOpt } from '../validate/dependency-tag-validate.js';
import { FileUtil } from './file-util.js';
import { HarTargetUtil } from './har-target-util.js';
import { getPropertyKeepDependency } from './parameter-utils.js';
import { buildOptionManager } from '../project/build-option/build-mode-manager.js';

export type OhosPackageJson = PackageJson & {
  ohos?: {
    org: string;
    artifactType: string;
  };
  artifactType?: string;
};

interface FileInfo {
  timeStamp: number;
  fileContent: any;
}
const json5Map: Map<string, FileInfo> = hvigorCore.getCache('JSON_CACHE');
export function getJson5Obj(filePath: string) {
  const timeStamp = fs.statSync(filePath).mtime.getTime();
  if (json5Map.get(filePath)?.timeStamp !== timeStamp) {
    json5Map.set(filePath, {
      timeStamp,
      fileContent: Json5Reader.getJson5Obj(filePath),
    });
  }

  // Safety: 上面已经保证curPkgJsonPath对应的value非空
  return json5Map.get(filePath)!.fileContent;
}

/**
 * 最小化hsp中的依赖，只保留hsp中的hsp相关依赖并删除devDependencies中的依赖
 *
 * @param packageJsonObj  oh-package.json5文件对象
 * @param service  ModuleTaskService
 * @param packageManagerPath  oh-package.json5的路径
 */
export function minimizeHspDependencies(packageJsonObj: any, service: ModuleTaskService, packageManagerPath: string) {
  if (getPropertyKeepDependency()) {
    return;
  }
  packageJsonObj.dependencies = getDependenciesWithoutHar(DependencyEnum.DEPENDENCIES, service, packageManagerPath);
  packageJsonObj.dynamicDependencies = getDependenciesWithoutHar(DependencyEnum.DYNAMIC_DEPENDENCIES, service, packageManagerPath);
  if (packageJsonObj.devDependencies) {
    delete packageJsonObj.devDependencies;
  }
}

/**
 * 打包hsp时dependencies依赖会排除hsp以外的其他依赖
 *
 * @param dependencyEnum 依赖类型
 * @param service  ModuleTaskService
 * @param packageManagerPath  oh-package.json5的路径
 * @private
 */
export function getDependenciesWithoutHar(dependencyEnum: DependencyEnum, service: ModuleTaskService, packageManagerPath: string) {
  const dependencies: any = {};
  const hspDependencies = service.getHspDependencies().filter((item) => item.getDependencyEnum() === dependencyEnum);
  if (hspDependencies.length === 0) {
    return {};
  }
  const pathParamsObj: pathParamsOpt = {
    parameterFilePath: service.getProjectModel().getParameterFileAbsolutePath(),
    ohPackageFilePath: packageManagerPath,
  };
  hspDependencies.forEach((dependency) => {
    const dependencyName = dependency.getDependencyName();
    dependencies[dependencyName] = FileUtil.extracted(
      dependency.getDependedVersion(),
      service.getModuleModel().getParentProject().getParameterFileObj(),
      pathParamsObj,
    );
  });
  return dependencies;
}

/**
 * 获取本地依赖har模块的当前target资源路径集合
 * @private
 */
export function getLocalDepHarTargetSources(targetTaskService: TargetTaskService, harDependency: Dependency, projectModule: ProjectModel){
  const harDepTargetResPaths: string[] = [];
  // 获取本地依赖的har模块的target
  const depHarTargets = HarTargetUtil.calDepHarTargets(targetTaskService);
  const harDependencyModule = DependencyManager.getModuleModelByDependency(harDependency, projectModule);
  const harDepModulePath = harDependencyModule?.getModule().getNodeDir();
  const harDepModuleName = harDependencyModule?.getModule().getName();
  const depHarTarget = harDepModuleName ? depHarTargets.get(harDepModuleName) : 'default';
  const depHarTargetBuildOpt = harDependencyModule?.getTargetOptions().filter((targetOption)=>{
    return targetOption.name === depHarTarget;
  });
  const directories = depHarTargetBuildOpt ? depHarTargetBuildOpt[0].resource?.directories : undefined;
  // 如果directories设置了路径，则获取directories里的资源路径
  if (directories?.length && harDepModulePath) {
    directories.forEach((directory) => {
      const directoryResPath = path.resolve(harDepModulePath, directory);
      if (fs.existsSync(directoryResPath)) {
        harDepTargetResPaths?.push(directoryResPath);
      }
    });
  }
  // 如果没有设置directories，或者directories值为空数组，则返回默认路径
  if (!directories?.length && harDepModulePath) {
    const defaultResPath = path.resolve(harDepModulePath, CommonConst.SRC_MAIN_RESOURCES);
    if (fs.existsSync(defaultResPath)) {
      harDepTargetResPaths?.push(defaultResPath);
    }
  }
  return harDepTargetResPaths;
}

/**
 * 获取远程har（产物态）模块的资源路径集合，产物态和源码态有一点区别：若在打包时target的resource/directories中配置了资源路径，则只会把配置的
 * 资源路径达到har包里，也就是说这种情况下产物har里不存在默认资源路径；但是当resource/directories是空时，会将默认资源路径达到包里
 * @param harDependency
 */
export function getRemoteDepHarTargetSources(harDependency: Dependency){
  const depHarResPaths: string[] = [];
  const dependencyRootPath = harDependency.getDependencyRootPath();
  const ohPackageJsonOpt: OhPackageJsonOpt = getJson5Obj(path.resolve(dependencyRootPath, CommonConst.OH_PACKAGE_JSON5));
  const resDirectories = ohPackageJsonOpt.metadata?.resource?.directories;
  if (resDirectories?.length) {
    resDirectories.forEach((directory) => {
      const directoryResPath = path.resolve(dependencyRootPath, directory);
      if (fs.existsSync(directoryResPath)) {
        depHarResPaths?.push(directoryResPath);
      }
    });
  }
  const defaultResPath = path.resolve(dependencyRootPath, CommonConst.SRC_MAIN_RESOURCES);
  if (!depHarResPaths.includes(defaultResPath) && fs.existsSync(defaultResPath)) {
    depHarResPaths?.push(defaultResPath);
  }
  return depHarResPaths;
}

/**
 * 获取本地依赖的路由表数据
 * @param projectModel
 * @param targetTaskService
 * @param dependency
 */
export function getLocalDependencyRouterMap(projectModel: ProjectModel, targetTaskService: TargetTaskService, dependency: Dependency) {
  const moduleModel = DependencyManager.getModuleModelByDependency(dependency, projectModel);
  const moduleName2Target = HarTargetUtil.calDepHarTargets(targetTaskService);
  const targetName = moduleModel && moduleName2Target.get(moduleModel.getName());
  return DependencyManager.getLocalDependencyRouterMapObjList(dependency, projectModel, targetName);
}

/**
 * 基于target差异化获取依赖的buildOptions
 * @param dependency
 * @param moduleName2TargetName
 */
export function getLocalDependencyBuildOptions(dependency: Dependency, moduleName2TargetName: Map<string, string>) {
  const moduleName = dependency.getModuleJsonObj()?.module.name ?? dependency.getPackageName();
  const targetName = moduleName2TargetName.get(moduleName) ?? 'default';
  return buildOptionManager.getTargetBuildOption(moduleName, targetName);
}
